home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / time.c < prev    next >
C/C++ Source or Header  |  1998-12-09  |  19KB  |  831 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: time.c,v 1.11 1998/04/14 00:16:27 drd Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - time.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. /* some systems may not implement time very well ; in particular,
  39.  * things might break as the year 2000 approaches.
  40.  * This module either adds a routine gstrptime() to read a formatted time,
  41.  * augmenting the standard suite of time routines provided by ansi,
  42.  * or it completely replaces the whole lot with a new set of routines,
  43.  * which count time relative to the year 2000. Default is to use the
  44.  * new routines. define USE_SYSTEM_TIME to use the system routines, at your
  45.  * own risk. One problem in particular is that not all systems allow
  46.  * the time with integer value 0 to be represented symbolically, which
  47.  * prevents use of relative times.
  48.  */
  49.  
  50.  
  51. #include "plot.h"
  52.  
  53. /* build as a standalone test */
  54.  
  55. #ifdef TEST_TIME
  56.  
  57. # ifdef HAVE_SYS_TIMEB_H
  58. #  include <sys/timeb.h>
  59. #else
  60. /* declare struct timeb */
  61. extern int ftime(struct timeb *);
  62. #endif
  63.  
  64. # define int_error(x,y) fprintf(stderr, "Error: " x "\n")
  65. # define int_warn(x,y) fprintf(stderr, "Warn: " x "\n")
  66.  
  67. /* need (only) these from plot.h */
  68. # define ZERO_YEAR    2000
  69. /* 1st jan, 2000 is a Saturday (cal 1 2000 on unix) */
  70. # define JAN_FIRST_WDAY 6
  71.  
  72. /*  zero gnuplot (2000) - zero system (1970) */
  73. # define SEC_OFFS_SYS    946684800.0
  74.  
  75. /* avg, incl. leap year */
  76. # define YEAR_SEC    31557600.0
  77.  
  78. /* YEAR_SEC / 12 */
  79. # define MON_SEC        2629800.0
  80.  
  81. # define WEEK_SEC    604800.0
  82. # define DAY_SEC        86400.0
  83.  
  84. /*forward decls */
  85. extern char *abbrev_month_names[];
  86. extern char *full_month_names[];
  87. extern char *abbrev_day_names[];
  88. extern char *full_day_names[];
  89.  
  90. #else /* TEST_TIME */
  91.  
  92. # include "setshow.h"        /* for month names etc */
  93.  
  94. #endif /* TEST_TIME */
  95.  
  96. static char *read_int __PROTO((char *s, int nr, int *d));
  97. static int gdysize __PROTO((int yr));
  98.  
  99.  
  100. static char *
  101.  read_int(s, nr, d)
  102. char *s;
  103. int nr, *d;
  104. {
  105.     int result = 0;
  106.  
  107.     while (--nr >= 0 && *s >= '0' && *s <= '9')
  108.     result = result * 10 + (*s++ - '0');
  109.  
  110.     *d = result;
  111.     return (s);
  112. }
  113.  
  114.  
  115.  
  116. #ifndef USE_SYSTEM_TIME
  117.  
  118. /* a new set of routines to completely replace the ansi ones
  119.  * Use at your own risk
  120.  */
  121.  
  122.  
  123. static int mndday[12] =
  124. {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  125.  
  126. static int xstrftime __PROTO((char *buf, int bufsz, char *fmt, struct tm * tm));
  127.  
  128. /* days in year */
  129. static int gdysize(yr)
  130. int yr;
  131. {
  132.  
  133.     if (!(yr % 4)) {
  134.     if ((!(yr % 100)) && yr % 400)
  135.         return (365);
  136.     return (366);
  137.     }
  138.     return (365);
  139. }
  140.  
  141.  
  142. /* new strptime() and gmtime() to allow time to be read as 24 hour,
  143.  * and spaces in the format string. time is converted to seconds from
  144.  * year 2000.... */
  145.  
  146. char *
  147.  gstrptime(s, fmt, tm)
  148. char *s;
  149. char *fmt;
  150. struct tm *tm;
  151. {
  152.     int yday, date;
  153.  
  154.     date = yday = 0;
  155.     tm->tm_mday = 1;
  156.     tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
  157.     /* make relative times work (user-defined tic step) */
  158.     tm->tm_year = ZERO_YEAR;
  159.  
  160.     /* we do not yet calculate wday or yday, so make them illegal
  161.      * [but yday will be read by %j]
  162.      */
  163.  
  164.     tm->tm_yday = tm->tm_wday = -1;
  165.  
  166.     while (*fmt) {
  167.     if (*fmt != '%') {
  168.         if (*fmt == ' ') {
  169.         /* space in format means zero or more spaces in input */
  170.         while (*s == ' ')
  171.             ++s;
  172.         ++fmt;
  173.         continue;
  174.         } else if (*fmt == *s) {
  175.         ++s;
  176.         ++fmt;
  177.         continue;
  178.         } else
  179.         break;        /* literal match has failed */
  180.     }
  181.     /* we are processing a percent escape */
  182.  
  183.     switch (*++fmt) {
  184.     case 'b':        /* abbreviated month name */
  185.         {
  186.         int m;
  187.         for (m = 0; m < 12; ++m)
  188.             if (strnicmp(s, abbrev_month_names[m], strlen(abbrev_month_names[m])) == 0) {
  189.             s += strlen(abbrev_month_names[m]);
  190.             goto found_abbrev_mon;
  191.             }
  192.         /* get here => not found */
  193.         int_warn("Bad abbreviated month name", NO_CARET);
  194.         m = 0;
  195.           found_abbrev_mon:
  196.         tm->tm_mon = m;
  197.         break;
  198.         }
  199.  
  200.     case 'B':        /* full month name */
  201.         {
  202.         int m;
  203.         for (m = 0; m < 12; ++m)
  204.             if (strnicmp(s, full_month_names[m], strlen(full_month_names[m])) == 0) {
  205.             s += strlen(full_month_names[m]);
  206.             goto found_full_mon;
  207.             }
  208.         /* get here => not found */
  209.         int_warn("Bad full month name", NO_CARET);
  210.         m = 0;
  211.           found_full_mon:
  212.         tm->tm_mon = m;
  213.         break;
  214.         }
  215.  
  216.     case 'd':        /* read a day of month */
  217.         s = read_int(s, 2, &tm->tm_mday);
  218.         date++;
  219.         break;
  220.  
  221.     case 'm':        /* month number */
  222.         s = read_int(s, 2, &tm->tm_mon);
  223.         date++;
  224.         --tm->tm_mon;
  225.         break;
  226.  
  227.     case 'y':        /* year number */
  228.         s = read_int(s, 2, &tm->tm_year);
  229.         date++;
  230.         tm->tm_year += 1900;
  231.         break;
  232.  
  233.     case 'Y':
  234.         s = read_int(s, 4, &tm->tm_year);
  235.         date++;
  236.         /* tm->tm_year -= 1900; */
  237.         /* HOE tm->tm_year %= 100; */
  238.         break;
  239.  
  240.     case 'j':
  241.         s = read_int(s, 3, &tm->tm_yday);
  242.         tm->tm_yday--;
  243.         date++;
  244.         yday++;
  245.         break;
  246.  
  247.     case 'H':
  248.         s = read_int(s, 2, &tm->tm_hour);
  249.         break;
  250.  
  251.     case 'M':
  252.         s = read_int(s, 2, &tm->tm_min);
  253.         break;
  254.  
  255.     case 'S':
  256.         s = read_int(s, 2, &tm->tm_sec);
  257.         break;
  258.  
  259.     default:
  260.         int_warn("Bad time format in string", NO_CARET);
  261.     }
  262.     fmt++;
  263.     }
  264.  
  265.     FPRINTF((stderr, "read date-time : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
  266.  
  267.     /* now check the date/time entered, normalising if necessary
  268.      * read_int cannot read a -ve number, but can read %m=0 then decrement
  269.      * it to -1
  270.      */
  271.  
  272. #define S (tm->tm_sec)
  273. #define M (tm->tm_min)
  274. #define H (tm->tm_hour)
  275.  
  276.     if (S >= 60) {
  277.     M += S / 60;
  278.     S %= 60;
  279.     }
  280.     if (M >= 60) {
  281.     H += M / 60;
  282.     M %= 60;
  283.     }
  284.     if (H >= 24) {
  285.     if (yday)
  286.         tm->tm_yday += H / 24;
  287.     tm->tm_mday += H / 24;
  288.     H %= 24;
  289.     }
  290. #undef S
  291. #undef M
  292. #undef H
  293.  
  294.     FPRINTF((stderr, "normalised time : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
  295.  
  296.     if (date) {
  297.     if (yday) {
  298.  
  299.         if (tm->tm_yday < 0)
  300.         int_error("Illegal day of year", NO_CARET);
  301.  
  302.         /* we just set month to jan, day to yday, and let the
  303.          * normalising code do the work.
  304.          */
  305.  
  306.         tm->tm_mon = 0;
  307.         /* yday is 0->365, day is 1->31 */
  308.         tm->tm_mday = tm->tm_yday + 1;
  309.     }
  310.     if (tm->tm_mon < 0) {
  311.         int_error("illegal month", NO_CARET);
  312.         return (NULL);
  313.     }
  314.     if (tm->tm_mday < 1) {
  315.         int_error("illegal day of month", NO_CARET);
  316.         return (NULL);
  317.     }
  318.     if (tm->tm_mon > 11) {
  319.         tm->tm_year += tm->tm_mon / 12;
  320.         tm->tm_mon %= 12;
  321.     } {
  322.         int days_in_month;
  323.         while (tm->tm_mday > (days_in_month = (mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365))))) {
  324.         if (++tm->tm_mon == 12) {
  325.             ++tm->tm_year;
  326.             tm->tm_mon = 0;
  327.         }
  328.         tm->tm_mday -= days_in_month;
  329.         }
  330.     }
  331.     }
  332.     return (s);
  333. }
  334.  
  335. int gstrftime(s, bsz, fmt, l_clock)
  336. char *s;
  337. int bsz;
  338. char *fmt;
  339. double l_clock;
  340. {
  341.     struct tm tm;
  342.  
  343.     ggmtime(&tm, l_clock);
  344. #if 0
  345.     if ((tm.tm_zone = (char *) malloc(strlen(xtm->tm_zone) + 1)))
  346.     strcpy(tm.tm_zone, xtm->tm_zone);
  347.     /* printf("zone: %s - %s\n",tm.tm_zone,xtm->tm_zone); */
  348. #endif
  349.  
  350.     return (xstrftime(s, bsz, fmt, &tm));
  351. }
  352.  
  353.  
  354. /* some shorthands : check that there is space in the output string
  355.  * Odd-looking defn is dangling-else-safe
  356.  */
  357. #define CHECK_SPACE(n) if ( (l+(n)) <= bsz) ; else return 0
  358.  
  359. /* copy a fixed string, checking that there's room */
  360. #define COPY_STRING(z) CHECK_SPACE(strlen(z)) ; strcpy(s, z)
  361.  
  362. /* format a string, using default spec if none given
  363.  * w and z are width and zero-flag
  364.  * dw and dz are the defaults for these
  365.  * In fact, CHECK_SPACE(w) is not a sufficient test, since
  366.  * sprintf("%2d", 365) outputs three characters
  367.  */
  368.  
  369. #define FORMAT_STRING(dz, dw, x)           \
  370.   if (w==0) { w=(dw); if (!z) z=(dz); }    \
  371.   CHECK_SPACE(w);                          \
  372.   sprintf(s, z ? "%0*d" : "%*d", w, (x) )
  373.  
  374. static int xstrftime(str, bsz, fmt, tm)
  375. char *str;            /* output buffer */
  376. int bsz;            /* space available */
  377. char *fmt;
  378. struct tm *tm;
  379. {
  380.     int l = 0;            /* chars written so far */
  381.  
  382.     char *s = str;
  383.  
  384.     memset(s, '\0', bsz);
  385.  
  386.     while (*fmt != '\0') {
  387.     if (*fmt != '%') {
  388.         if (l >= bsz)
  389.         return (0);
  390.         *s++ = *fmt++;
  391.         l++;
  392.     } else {
  393.  
  394.         /* set up format modifiers */
  395.         int w = 0;
  396.         int z = 0;
  397.         if (*++fmt == '0') {
  398.         z = 1;
  399.         ++fmt;
  400.         }
  401.         while (*fmt >= '0' && *fmt <= '9') {
  402.         w = w * 10 + (*fmt - '0');
  403.         ++fmt;
  404.         }
  405.  
  406.         switch (*fmt++) {
  407.         case '%':
  408.         CHECK_SPACE(1);
  409.         *s = '%';
  410.         break;
  411.  
  412.         case 'a':
  413.         COPY_STRING(abbrev_day_names[tm->tm_wday]);
  414.         break;
  415.  
  416.         case 'A':
  417.         COPY_STRING(full_day_names[tm->tm_wday]);
  418.         break;
  419.  
  420.         case 'b':
  421.         case 'h':
  422.         COPY_STRING(abbrev_month_names[tm->tm_mon]);
  423.         break;
  424.  
  425.         case 'B':
  426.         COPY_STRING(full_month_names[tm->tm_mon]);
  427.         break;
  428.  
  429.  
  430. #if 0
  431.         /* %x not currently supported, so neither is c */
  432.         case 'c':
  433.         if (!xstrftime(s, bsz - l, "%x %X", tm))
  434.             return (0);
  435.         break;
  436. #endif
  437.  
  438.         case 'd':
  439.         FORMAT_STRING(1, 2, tm->tm_mday);    /* %02d */
  440.         break;
  441.  
  442.         case 'D':
  443.         if (!xstrftime(s, bsz - l, "%m/%d/%y", tm))
  444.             return (0);
  445.         break;
  446.  
  447.         case 'H':
  448.         FORMAT_STRING(1, 2, tm->tm_hour);    /* %02d */
  449.         break;
  450.  
  451.         case 'I':
  452.         FORMAT_STRING(1, 2, tm->tm_hour % 12);    /* %02d */
  453.         break;
  454.  
  455.         case 'j':
  456.         FORMAT_STRING(1, 3, tm->tm_yday + 1);    /* %03d */
  457.         break;
  458.  
  459.         /* not in linux strftime man page. Not really needed now */
  460.         case 'k':
  461.         FORMAT_STRING(0, 2, tm->tm_hour);    /* %2d */
  462.         break;
  463.  
  464.         case 'l':
  465.         FORMAT_STRING(0, 2, tm->tm_hour % 12);    /* %2d */
  466.         break;
  467.  
  468.         case 'm':
  469.         FORMAT_STRING(1, 2, tm->tm_mon + 1);    /* %02d */
  470.         break;
  471.  
  472.         case 'M':
  473.         FORMAT_STRING(1, 2, tm->tm_min);    /* %02d */
  474.         break;
  475.  
  476.         case 'p':
  477.         CHECK_SPACE(2);
  478.         strcpy(s, (tm->tm_hour < 12) ? "am" : "pm");
  479.         break;
  480.  
  481.         case 'r':
  482.         if (!xstrftime(s, bsz - l, "%I:%M:%S %p", tm))
  483.             return (0);
  484.         break;
  485.  
  486.         case 'R':
  487.         if (!xstrftime(s, bsz - l, "%H:%M", tm))
  488.             return (0);
  489.         break;
  490.  
  491.         case 'S':
  492.         FORMAT_STRING(1, 2, tm->tm_sec);    /* %02d */
  493.         break;
  494.  
  495.         case 'T':
  496.         if (!xstrftime(s, bsz - l, "%H:%M:%S", tm))
  497.             return (0);
  498.         break;
  499.  
  500.         case 'W':        /* mon 1 day of week */
  501.         {
  502.             int week;
  503.             if (tm->tm_yday <= tm->tm_wday) {
  504.             week = 1;
  505.  
  506.             if ((tm->tm_mday - tm->tm_yday) > 4) {
  507.                 week = 52;
  508.             }
  509.             if (tm->tm_yday == tm->tm_wday && tm->tm_wday == 0)
  510.                 week = 52;
  511.  
  512.             } else {
  513.  
  514.             /* sun prev week */
  515.             int bw = tm->tm_yday - tm->tm_wday;
  516.  
  517.             if (tm->tm_wday > 0)
  518.                 bw += 7;    /* sun end of week */
  519.  
  520.             week = (int) bw / 7;
  521.  
  522.             if ((bw % 7) > 2)    /* jan 1 is before friday */
  523.                 week++;
  524.             }
  525.             FORMAT_STRING(1, 2, week);    /* %02d */
  526.             break;
  527.         }
  528.  
  529.         case 'U':        /* sun 1 day of week */
  530.         {
  531.             int week, bw;
  532.  
  533.             if (tm->tm_yday <= tm->tm_wday) {
  534.             week = 1;
  535.             if ((tm->tm_mday - tm->tm_yday) > 4) {
  536.                 week = 52;
  537.             }
  538.             } else {
  539.             /* sat prev week */
  540.             bw = tm->tm_yday - tm->tm_wday - 1;
  541.             if (tm->tm_wday >= 0)
  542.                 bw += 7;    /* sat end of week */
  543.             week = (int) bw / 7;
  544.             if ((bw % 7) > 1) {    /* jan 1 is before friday */
  545.                 week++;
  546.             }
  547.             }
  548.             FORMAT_STRING(1, 2, week);    /* %02d */
  549.             break;
  550.         }
  551.  
  552.         case 'w':        /* day of week, sun=0 */
  553.         FORMAT_STRING(1, 2, tm->tm_wday);    /* %02d */
  554.         break;
  555.  
  556.         case 'y':
  557.         FORMAT_STRING(1, 2, tm->tm_year % 100);        /* %02d */
  558.         break;
  559.  
  560.         case 'Y':
  561.         FORMAT_STRING(1, 4, tm->tm_year);    /* %04d */
  562.         break;
  563.  
  564. #if 0
  565.         case 'Z':
  566.         COPY_STRING(tm->tm_zone);
  567.         break;
  568. #endif
  569.         }            /* switch */
  570.  
  571.         while (*s != '\0') {
  572.         s++;
  573.         l++;
  574.         }
  575.     }
  576.     }
  577.     return (l);
  578. }
  579.  
  580.  
  581.  
  582. /* time_t  */
  583. double gtimegm(tm)
  584. struct tm *tm;
  585. {
  586.     register int i;
  587.     /* returns sec from year ZERO_YEAR, defined in plot.h */
  588.     double dsec;
  589.  
  590.     dsec = 0;
  591.     if (tm->tm_year < ZERO_YEAR) {
  592.     for (i = tm->tm_year; i < ZERO_YEAR; i++) {
  593.         dsec -= (double) gdysize(i);
  594.     }
  595.     } else {
  596.     for (i = ZERO_YEAR; i < tm->tm_year; i++) {
  597.         dsec += (double) gdysize(i);
  598.     }
  599.     }
  600.     if (tm->tm_mday > 0) {
  601.     for (i = 0; i < tm->tm_mon; i++) {
  602.         dsec += (double) mndday[i] + (i == 1 && (gdysize(tm->tm_year) > 365));
  603.     }
  604.     dsec += (double) tm->tm_mday - 1;
  605.     } else {
  606.     dsec += (double) tm->tm_yday;
  607.     }
  608.     dsec *= (double) 24;
  609.  
  610.     dsec += tm->tm_hour;
  611.     dsec *= 60.0;
  612.     dsec += tm->tm_min;
  613.     dsec *= 60.0;
  614.     dsec += tm->tm_sec;
  615.  
  616.     FPRINTF((stderr, "broken-down time : %d/%d/%d:%d:%d:%d = %g seconds\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec, dsec));
  617.  
  618.     return (dsec);
  619. }
  620.  
  621. int ggmtime(tm, l_clock)
  622. struct tm *tm;
  623. /* time_t l_clock; */
  624. double l_clock;
  625. {
  626.     /* l_clock is relative to ZERO_YEAR, jan 1, 00:00:00,defined in plot.h */
  627.     int i, days;
  628.  
  629.     /* dodgy way of doing wday - i hope it works ! */
  630.  
  631.     int wday = JAN_FIRST_WDAY;    /* eg 6 for 2000 */
  632.  
  633.     FPRINTF((stderr, "%g seconds = ", l_clock));
  634.  
  635.     tm->tm_year = ZERO_YEAR;
  636.     tm->tm_mday = tm->tm_yday = tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
  637.     if (l_clock < 0) {
  638.     while (l_clock < 0) {
  639.         int days_in_year = gdysize(--tm->tm_year);
  640.         l_clock += days_in_year * DAY_SEC;    /* 24*3600 */
  641.         /* adding 371 is noop in modulo 7 arithmetic, but keeps wday +ve */
  642.         wday += 371 - days_in_year;
  643.     }
  644.     } else {
  645.     for (;;) {
  646.         int days_in_year = gdysize(tm->tm_year);
  647.         if (l_clock < days_in_year * DAY_SEC)
  648.         break;
  649.         l_clock -= days_in_year * DAY_SEC;
  650.         tm->tm_year++;
  651.         /* only interested in result modulo 7, but %7 is expensive */
  652.         wday += (days_in_year - 364);
  653.     }
  654.     }
  655.     tm->tm_yday = (int) (l_clock / DAY_SEC);
  656.     l_clock -= tm->tm_yday * DAY_SEC;
  657.     tm->tm_hour = (int) l_clock / 3600;
  658.     l_clock -= tm->tm_hour * 3600;
  659.     tm->tm_min = (int) l_clock / 60;
  660.     l_clock -= tm->tm_min * 60;
  661.     tm->tm_sec = (int) l_clock;
  662.  
  663.     days = tm->tm_yday;
  664.  
  665.     /* wday%7 should be day of week of first day of year */
  666.     tm->tm_wday = (wday + days) % 7;
  667.  
  668.     while (days >= (i = mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365)))) {
  669.     days -= i;
  670.     tm->tm_mon++;
  671.     }
  672.     tm->tm_mday = days + 1;
  673.  
  674.     FPRINTF((stderr, "broken-down time : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
  675.  
  676.     return (0);
  677. }
  678.  
  679.  
  680.  
  681.  
  682. #else /* USE_SYSTEM_TIME */
  683.  
  684. /* define gnu time routines in terms of system time routines */
  685.  
  686. int gstrftime(buf, bufsz, fmt, l_clock)
  687. char *buf;
  688. int bufsz;
  689. char *fmt;
  690. double l_clock;
  691. {
  692.     time_t t = (time_t) l_clock;
  693.     return strftime(buf, bufsz, fmt, gmtime(&t));
  694. }
  695.  
  696. double gtimegm(tm)
  697. struct tm *tm;
  698. {
  699.     return (double) mktime(tm);
  700. }
  701.  
  702. int ggmtime(tm, l_clock)
  703. struct tm *tm;
  704. double l_clock;
  705. {
  706.     time_t t = (time_t) l_clock;
  707.     struct tm *m = gmtime(&t);
  708.     *tm = *m;            /* can any non-ansi compilers not do this ? */
  709. }
  710.  
  711. #define NOTHING
  712. #define LETTER(L, width, field, extra) \
  713.   case L: s=read_int(s,width,&tm->field); extra; continue
  714.  
  715. /* supplemental routine gstrptime() to read a formatted time */
  716.  
  717. char *
  718.  gstrptime(s, fmt, tm)
  719. char *s;
  720. char *fmt;
  721. struct tm *tm;
  722. {
  723.     FPRINTF((stderr, "gstrptime(\"%s\", \"%s\")\n", s, fmt));
  724.  
  725.     /* linux does not appear to like years before 1902
  726.      * NT complains if its before 1970
  727.      * initialise fields to midnight, 1st Jan, 1970 (for relative times)
  728.      */
  729.     tm->tm_sec = tm->tm_min = tm->tm_hour = 0;
  730.     tm->tm_mday = 1;
  731.     tm->tm_mon = 0;
  732.     tm->tm_year = 70;
  733.     /* oops - it goes wrong without this */
  734.     tm->tm_isdst = 0;
  735.  
  736.     for (; *fmt && *s; ++fmt) {
  737.     if (*fmt != '%') {
  738.         if (*s != *fmt)
  739.         return s;
  740.         ++s;
  741.         continue;
  742.     }
  743.     assert(*fmt == '%');
  744.  
  745.     switch (*++fmt) {
  746.     case 0:
  747.         /* uh oh - % is last character in format */
  748.         return s;
  749.     case '%':
  750.         /* literal % */
  751.         if (*s++ != '%')
  752.         return s - 1;
  753.         continue;
  754.  
  755.         LETTER('d', 2, tm_mday, NOTHING);
  756.         LETTER('m', 2, tm_mon, NOTHING);
  757.         LETTER('y', 2, tm_year, NOTHING);
  758.         LETTER('Y', 4, tm_year, tm->tm_year -= 1900);
  759.         LETTER('H', 2, tm_hour, NOTHING);
  760.         LETTER('M', 2, tm_min, NOTHING);
  761.         LETTER('S', 2, tm_sec, NOTHING);
  762.  
  763.     default:
  764.         int_error("incorrect time format character", NO_CARET);
  765.     }
  766.     }
  767.  
  768.     FPRINTF((stderr, "Before mktime : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
  769.     /* mktime range-checks the time */
  770.  
  771.     if (mktime(tm) == -1) {
  772.     FPRINTF((stderr, "mktime() was not happy\n"));
  773.     int_error("Invalid date/time [mktime() did not like it]", NO_CARET);
  774.     }
  775.     FPRINTF((stderr, "After mktime : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
  776.  
  777.     return s;
  778. }
  779.  
  780.  
  781. #endif /* USE_SYSTEM_TIME */
  782.  
  783.  
  784. #ifdef TEST_TIME
  785.  
  786. char *abbrev_month_names[] =
  787. {"jan", "feb", "mar", "apr", "may", "jun", "jul",
  788.  "aug", "sep", "oct", "nov", "dec"};
  789. char *full_month_names[] =
  790. {"January", "February", "March", "April", "May",
  791. "June", "July", "August", "September", "October", "November", "December"};
  792.  
  793. char *abbrev_day_names[] =
  794. {"sun", "mon", "tue", "wed", "thu", "fri", "sat"};
  795. char *full_day_names[] =
  796. {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
  797.  
  798.  
  799.  
  800. /* either print current time using supplied format, or read
  801.  * supplied time using supplied format
  802.  */
  803.  
  804.  
  805. int main(argc,argv)
  806. int argc;
  807. char *argv[];
  808. {
  809.     char output[80];
  810.  
  811.     if (argc < 2) {
  812.     fputs("usage : test 'format' ['time']\n", stderr);
  813.     exit(EXIT_FAILURE);
  814.     }
  815.     if (argc == 2) {
  816.     struct timeb now;
  817.     struct tm *tm;
  818.     ftime(&now);
  819.     tm = gmtime(&now.time);
  820.     xstrftime(output, 80, argv[1], tm);
  821.     puts(output);
  822.     } else {
  823.     struct tm tm;
  824.     gstrptime(argv[2], argv[1], &tm);
  825.     puts(asctime(&tm));
  826.     }
  827.     exit(EXIT_SUCCESS);
  828. }
  829.  
  830. #endif /* TEST_TIME */
  831.